package io.gitee.tziye.core.kv.impl;

import io.gitee.tziye.common.Constants;
import io.gitee.tziye.common.RenaiUtil;
import io.gitee.tziye.common.ValueResult;
import io.gitee.tziye.core.instance.DefaultRenaiClient;
import io.gitee.tziye.core.kv.PairOperator;
import io.gitee.tziye.core.kv.RenaiKey;
import io.gitee.tziye.core.kv.RenaiValue;
import io.gitee.tziye.enums.KvType;
import io.gitee.tziye.jdbc.JdbcProxy;
import io.gitee.tziye.jdbc.ProcedureResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import static io.gitee.tziye.common.Constants.VALUE;

public class DefaultPairOperator extends PairOperator {

    private final KvCommonOperator kvCommonOperator;
    private final JdbcProxy jdbcProxy;

    public DefaultPairOperator(DefaultRenaiClient renaiClient) {
        super(renaiClient);
        kvCommonOperator = new KvCommonOperator(renaiClient);
        jdbcProxy = renaiClient.getJdbcProxy();
    }

    @Override
    public void saveKey(String key, Integer expireSeconds) {
        throw new UnsupportedOperationException();
    }

    @Override
    public RenaiKey key(String key) {
        return kvCommonOperator.key(key, KvType.Pair);
    }

    @Override
    public List<RenaiKey> keys(List<String> keys) {
        return kvCommonOperator.keys(keys, KvType.Pair);
    }

    @Override
    public List<RenaiKey> keys() {
        return kvCommonOperator.keys(KvType.Pair);
    }

    @Override
    public List<RenaiKey> like(String pattern) {
        return kvCommonOperator.like(pattern, KvType.Pair);
    }

    @Override
    public List<RenaiKey> regexp(String pattern) {
        return kvCommonOperator.regexp(pattern, KvType.Pair);
    }

    @Override
    public List<RenaiValue> values(String key) {
        throw new UnsupportedOperationException();
    }

    @Override
    public int total() {
        return kvCommonOperator.total(KvType.Pair);
    }

    @Override
    public int size(String key) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void expire(String key, int expireSeconds) {
        kvCommonOperator.expire(key, expireSeconds, KvType.Pair);
    }

    @Override
    public boolean exists(String key) {
        return kvCommonOperator.exists(key, KvType.Pair);
    }

    @Override
    public <T> boolean contains(String key, T value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public int clear(String key) {
        throw new UnsupportedOperationException();
    }

    @Override
    public <T> boolean remove(String key, T value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public <T> int removeValues(String key, Collection<T> values) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean delete(String key) {
        return kvCommonOperator.delete(key, KvType.Pair);
    }

    @Override
    public int delete(Collection<String> keys) {
        return kvCommonOperator.delete(keys, KvType.Pair);
    }

    @Override
    public void flush() {
        kvCommonOperator.flush(KvType.Pair);
    }

    @Override
    public <T> void set(String key, T value) {
        assert StringUtils.isNotBlank(key) && value != null;
        String sql = """
                INSERT INTO renai_kv_pair(k, v) VALUES (?, ?) ON DUPLICATE KEY UPDATE v = VALUES(v),
                    expire_time = IF(expire_time <= NOW(), NULL, expire_time), update_time = NOW()""";
        jdbcProxy.update(sql, key, RenaiUtil.string(value));
    }

    @Override
    public <T> void set(String key, T value, int expireSeconds) {
        assert StringUtils.isNotBlank(key) && value != null && expireSeconds > 0;
        String sql = """
                INSERT INTO renai_kv_pair(k, v, expire_time) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL ? SECOND))
                ON DUPLICATE KEY UPDATE v = VALUES(v), expire_time = VALUES(expire_time), update_time = NOW()""";
        jdbcProxy.update(sql, key, RenaiUtil.string(value), expireSeconds);
    }

    @Override
    public <T> T get(String key, Class<T> clazz) {
        assert StringUtils.isNotBlank(key) && clazz != null;
        String sql = "SELECT v FROM renai_kv_pair_valid WHERE k = ?";
        List<String> values = jdbcProxy.queryForList(sql, String.class, key);
        if (CollectionUtils.isEmpty(values)) {
            return null;
        }
        return RenaiUtil.parse(values.get(0), clazz);
    }

    @Override
    public long incr(String key, long num) {
        assert StringUtils.isNotBlank(key);
        Map<String, Object> params = procedureParams(key);
        params.put(VALUE, num);
        ProcedureResult result = jdbcProxy.call(Constants.KV_PAIR_INCR, params);
        return result.get(ValueResult.class).getLv();
    }

}
